#include <base/reflection.hpp>

namespace reflect{
const std::string& TypeDescriptor::GetName() const
{
    return name_;
}

const std::vector<MemberVariable>& TypeDescriptor::GetMemberVariables() const 
{
    return member_vars_;
}

const std::vector<MemberFunction>& TypeDescriptor::GetMemberFunctions() const 
{
    return member_funcs_;
}

MemberVariable TypeDescriptor::GetMemberVariable(const std::string& name) const 
{
    for (auto& var : member_vars_) {
        if (var.GetName() == name) {
            return var;
        }
    }
    return MemberVariable();
}

MemberFunction TypeDescriptor::GetMemberFunction(const std::string& name) const 
{
    for (auto& var : member_funcs_) {
        if (var.GetName() == name) {
            return var;
        }
    }
    return MemberFunction();
}

const std::string& MemberVariable::GetName() const 
{
    return name_;
}


const std::string& MemberFunction::GetName() const
{
    return name_;
}

bool MemberFunction::IsConst() const 
{
    return is_const_;
}

Registry Registry::instance_;

Registry::Registry()
{
    
}

Registry& Registry::GetInstance() 
{
    return instance_;
}

std::vector<TypeDescriptor*> Registry::GetAllTypeDescriptor() const 
{
    std::vector<TypeDescriptor*> res;
    for (auto& desc: descs_) {
        res.push_back((desc.second).get());
    }
    return res;
}

TypeDescriptor* Registry::FindTypeDescriptor(const std::string& name) const 
{
    auto it = descs_.find(name);
    if (it != descs_.end()) {
        return (it -> second).get();
    }
    return nullptr;
}

void Registry::Register(std::unique_ptr<TypeDescriptor> desc)
{
    auto name = desc->GetName();
    descs_[name] = std::move(desc);
}

void Registry::Clear()
{
    decltype(descs_) tmp;
    descs_.swap(tmp);
}

RawTypeDescriptorBuilder::RawTypeDescriptorBuilder(const std::string& name)
    : desc_(std::make_unique<TypeDescriptor>())
{
    desc_->name_ = name;
}

RawTypeDescriptorBuilder:: ~RawTypeDescriptorBuilder()
{
    Registry::GetInstance().Register(std::move(desc_));
}

std::vector<TypeDescriptor*> Get() 
{
    return Registry::GetInstance().GetAllTypeDescriptor();
}

TypeDescriptor& GetByName(const std::string& name) 
{
    return *Registry::GetInstance().FindTypeDescriptor(name);
}

}